#pragma once

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>

#include "error.hpp"      //错误
#include "ThreadPool.hpp" //线程池
#include "Task.hpp"       //任务
#include "log.hpp"        //日志
#include "daemon.hpp"     //守护进程

namespace ns_server
{
    static const uint16_t defaultport = 8081;
    static const int backlog = 32; // 用于listen函数中，backlog为TCP连接的最大数量

    using func_t = std::function<std::string(const std::string &)>; // 定义了一个名为func_t的类型别名。接受一个const std::string&类型的参数，并返回一个std::string类型的值

    class TcpServer; // 声明

    class ThreadData // 多线程相关数据
    {
    public:
        ThreadData(int fd, const std::string &ip, const uint16_t &port, TcpServer *ts)
            : sock(fd), clientip(ip), clientport(port), current(ts)
        {
        }

    public:
        int sock;
        std::string clientip;
        uint16_t clientport;
        TcpServer *current;
    };

    class TcpServer // TCP连接
    {
    public:
        TcpServer(func_t func, uint16_t port = defaultport)
            : _func(func), _port(port), _quit(true)
        {
        }
        ~TcpServer()
        {
        }

        void InitServer() // 初始化，建立TCP连接
        {
            // 1.创建套接字socket
            _ListenSock = socket(AF_INET, SOCK_STREAM, 0); // 创建IP，TCP套接字
            if (_ListenSock < 0)
            {
                // std::cerr << "create socket error" << std::endl;
                logMessage(Fatal, "create socket error, code: %d, error string: %s", errno, strerror(errno));
                exit(SOCKET_ERR);
            }
            logMessage(Info, "create socket success, code: %d, error string: %s", errno, strerror(errno));

            // 2.绑定bind
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = htonl(INADDR_ANY);
            if (bind(_ListenSock, (struct sockaddr *)&local, sizeof(local)) < 0)
            {
                logMessage(Fatal, "bind socket error, code: %d, error string: %s", errno, strerror(errno));
                // std::cerr << "bind socket error" << std::endl;
                exit(BIND_ERR);
            }
            logMessage(Info, "bind socket success, code: %d, error string: %s", errno, strerror(errno));

            // 3.监听
            if (listen(_ListenSock, backlog) < 0)
            {
                logMessage(Fatal, "listen socket error, code: %d, error string: %s", errno, strerror(errno));
                exit(LISTEN_ERR);
            }
            logMessage(Info, "listen socket success, code: %d, error string: %s", errno, strerror(errno));
        }

        void Start() // 执行服务
        {
            _quit = false;
            while (!_quit)
            {
                struct sockaddr_in client;
                socklen_t len = sizeof(client);
                // 获取连接accept
                int sock = accept(_ListenSock, (struct sockaddr *)&client, &len);
                if (sock < 0)
                {
                    // std::cerr << "accept error" << std::endl;
                    logMessage(Warning, "accept error, code: %d, error string: %s", errno, strerror(errno));
                    continue;
                }

                std::string clientip = inet_ntoa(client.sin_addr);
                uint16_t clientport = ntohs(client.sin_port);

                // 获取新连接成功，进行业务处理
                logMessage(Info, "获取新连接成功: %d from %d, who: %s - %d",
                           sock, _ListenSock, clientip.c_str(), clientport);

                // a.单进程
                // service(sock,clientip,clientport);

                // b.多进程
                //  pid_t id=fork();
                //  if(id<0)//错误
                //  {
                //      close(sock);
                //      continue;
                //  }
                //  else if(id==0)//子进程中
                //  //父进程文件描述符表会被子进程继承，子进程复制父进程文件描述符表
                //  {
                //      close(_ListenSock);
                //      if(fork()>0)exit(0);

                //     //子进程退出，孙子进程执行服务
                //     service(sock,clientip,clientport);
                //     exit(0);
                // }
                // close(sock);//父进程一定要关闭不需要的fd，避免fd泄露
                // pid_t ret=waitpid(id,nullptr,0);//阻塞式回收子进程，不推荐
                // pid_t ret=waitpid(id,nullptr,WNOHANG);//非阻塞回收子进程，也不推荐。因为子进程可能在获取连接accept处就阻塞
                // //推荐在函数开始增加函数signal(SIGCHLD,SIG_IGN);忽视子进程退出时发送的信号，避免产生僵尸进程
                // if(ret == id) std::cout << "wait child " << id << " success" << std::endl;

                // c.多线程，原生多线程库
                //???????
                pthread_t thread;
                ThreadData *td = new ThreadData(sock, clientip, clientport, this);
                pthread_create(&thread, nullptr, threadRoutine, td);

                // d.线程池
                Task t(sock, clientip, clientport, std::bind(&TcpServer::service, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                ThreadPool<Task>::getinstance()->pushTask(t);
            }
        }

        static void *threadRoutine(void *args) // 多线程回调函数
        {
            pthread_detach(pthread_self());

            ThreadData *td = static_cast<ThreadData *>(args);
            td->current->service(td->sock, td->clientip, td->clientport);
            delete td;
            return nullptr;
        }

        void service(int sock, const std::string &clientip, const uint16_t &clientport)
        {
            char buffer[1024];
            std::string who = clientip + "-" + std::to_string(clientport);

            // 方法二 使用日志
            ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
            if (s > 0)
            {
                buffer[s] = 0;
                std::string res = _func(buffer); // 进行回调
                // std::cout << who << ">>> " << res << std::endl;
                logMessage(Debug, "%s# %s", who.c_str(), res.c_str());
                write(sock, res.c_str(), res.size());
            }
            else if (s == 0)
            {
                // 对方将连接关闭了
                // std::cout << who << " quit, me too" << std::endl;
                logMessage(Info, "%s quit,me too", who.c_str());
            }
            else
            {
                // std::cerr << "read error: " << strerror(errno) << std::endl;
                logMessage(Error, "read error, %d:%s", errno, strerror(errno));
            }
            close(sock);

            // 方法一
            //  while (true)
            //  {
            //      ssize_t s = read(sock, buffer, sizeof(buffer) - 1); // 为什么这里使用read而不在UDP中使用呢？因为TCP是面向字节流的可靠连接传输，read就是流提取
            //      if (s > 0)
            //      {
            //          buffer[s] = 0;
            //          std::string res = _func(buffer); // 进行回调
            //          std::cout << who << ">>> " << res << std::endl;

            //         write(sock, res.c_str(), res.size());
            //     }
            //     else if (s == 0)
            //     {
            //         // 对方将连接关闭了
            //         close(sock);
            //         std::cout << who << " quit, me too" << std::endl;
            //         break;
            //     }
            //     else
            //     {
            //         close(sock);
            //         std::cerr << "read error: " << strerror(errno) << std::endl;
            //         break;
            //     }
            // }
        }

    private:
        func_t _func;    //
        uint16_t _port;  // 服务器端口号
        bool _quit;      // 判断用户是否断连
        int _ListenSock; // 监听socket描述符
    };
}